//
// Created by song on 16-12-31.
// function ir evaluator which perform data flow analysis(reaching definition)
//
//

#ifndef C0COMPILER_ABSTRACTIREVALUATOR_H
#define C0COMPILER_ABSTRACTIREVALUATOR_H


#include <set>
#include "IRVisitor.h"
#include "IR.h"
#include "DefUseChain.h"
#include "BasicBlock.h"

class BlockIREvaluator{

};

class AbstractIREvaluator: public IRVisitor{
    map<BasicBlock *, set<IR *> *> in;
    map<BasicBlock *, set<IR *> *> out;
    map<BasicBlock *, set<IR *> *> gen;
    vector<BasicBlock *> blockList;

    map<TmpVar*, vector<IR*>> varDefMap;
    map<TmpVar*, IR*> localVarDefMap; // in current block. can only be one def at one time.
    set<IR*>* inSet;
    set<TmpVar*> globalVar;
public:

    AbstractIREvaluator(
            map<BasicBlock *, set<IR *> *> in,
            map<BasicBlock *, set<IR *> *> out,
            map<BasicBlock *, set<IR *> *> gen,
            vector<BasicBlock *> blockList
    ):
            in(in),
            out(out),
            gen(gen),
            blockList(blockList)
    {


    }

    AbstractIREvaluator(set<IR *> *inSet, set<TmpVar *> &globalVars):

            inSet(inSet),
            globalVar(globalVars){
        set<IR*>::const_iterator iter=inSet->begin();
        while(iter!=inSet->end()){
            IR* ir = *iter;
            if(varDefMap.count(ir->result)==0){
                varDefMap[ir->result].push_back(ir);
            }
            iter++;
        }
    }

//    void findDef(IR* ir, TmpVar* var){
//        if(var==NULL || var->type!=TmpVar::VAR || globalVar.count(var)>0){
//            return;
//        }
//        if(localVarDefMap.count(var)>0){ // defined local
//            IR* defIR = localVarDefMap[var];
//            DefUseChain::addUsage(defIR, ir);
//        }else if(varDefMap.count(var)>0){  // defined in other block
//            vector<IR*> irList = varDefMap[var];
//            for(int i=0; i<irList.size(); i++){
//                DefUseChain::addUsage(irList[i], ir);
//            }
//            DefUseChain::join(irList);
//        }else{
//            Error::nextErrorDetail << "TmpVar " << var->name() <<" def not found!";
//            Error::internal(Error::Should_Not_Happen);
//        }
//    }
//
//    void define(IR* ir){
//        TmpVar* var = ir->result;
//        localVarDefMap[var] = ir;
//    }
//
//    void eval(){
//        for(int i=0; i<blockList.size(); i++) {
//            BasicBlock *b = blockList[i];
//
//            set<TmpVar*>* varGenerated = new set<TmpVar*>();
//            gen[b] = b->dataFlowGen(varGenerated);
////            varGen[b] = varGenerated;
//            in[b] =  new set<IR*>();
//            out[b] = new set<IR*>();
//        }
//    }
//
//    ReturnedObj *visit(IR *ir){
//        switch(ir->op){
//            case ADD:
//            case SUB:
//            case MUL:
//            case DIV:
//            case SGE:
//            case SG:
//            case SNE:
//            case SE:
//            case SLE:
//            case SL:
//            case DEFREF:  // these all use left, right and define new on result
//                findDef(ir, ir->left);
//                findDef(ir, ir->right);
//                define(ir);
//                break;
//            case JGE:
//            case JG:
//            case JNE:
//            case JE:
//            case JLE:
//            case JL:
//                findDef(ir, ir->left);
//                findDef(ir, ir->right);
//                break;
//            case ASSIGN: // use left, define result
//                findDef(ir, ir->left);
//                define(ir);
//                break;
//            case WRITECHAR:
//            case WRITE:
//            case PUSHPARAM:
//            case RETURN: // only use left. define nothing.
//                findDef(ir, ir->left);
//                break;
//            case ASSIGNARR: // define nothing but has side effect, use left/right/result
//                findDef(ir, ir->left);
//                findDef(ir, ir->right);
//                findDef(ir, ir->result);
//                break;
//            case READ:
//            case READCHAR:
//            case CALL:
//            case PUSHARR:
//            case POPPARAM: // use nothing but define result.
//                define(ir);
//                break;
//            case WRITESTR: // string are all global
//            case WRITELN:
//            case ARRAY:// global array
//            case ERROR:
//            case NOOP:
//            case JMP:
//            case FUNBEGIN:
//            case FUNEND:break;// do nothing.
//        }
//        return NULL;
//    }

};


#endif //C0COMPILER_ABSTRACTIREVALUATOR_H
